#ifndef __M_DB_H__
#define __M_DB_H__
#include "util.hpp"
#include <mutex>
#include <cassert>

class user_table
{
private:
    MYSQL *_mysql;     // mysql操作句柄
    std::mutex _mutex; // 互斥锁保护数据库的访问操作
public:
    user_table(const std::string &host,
               const std::string &username,
               const std::string &password,
               const std::string &dbname,
               uint16_t port = 3306)
    {
        _mysql = mysql_util::mysql_create(host, username, password, dbname, port);
        assert(_mysql != NULL);
    }

    ~user_table()
    {
        mysql_util::mysql_destroy(_mysql);
        _mysql = NULL;
    }

    // 注册时新增用户
    bool insert(Json::Value &user)
    {
        #define INSERT_USER "insert user values(null,'%s','%s',1200,0,0);"
        if (user["password"].isNull() || user["username"].isNull()) 
        {
                    DLOG("INPUT PASSWORD OR USERNAME");
                    return false;
        }
        
        char sql[4096] = {0};
        sprintf(sql,INSERT_USER,user["username"].asCString(),user["password"].asCString());
        bool ret = mysql_util::mysql_exec(_mysql,sql);
        if(ret == false)
        {
            ELOG("insert user info failed!");
            return false;
        }
        return true;
    }

    // 登录验证 并返回详细的用户信息
    bool login(Json::Value &user)
    {
        // 以用户名和密码共同作为查询条件来查询，若查询到数据则表示存在一致的，登录通过
        #define LOGIN_USER "select id,score,total_count,win_count from user where username='%s' and password=('%s');"
        char sql[4096] = {0};
        sprintf(sql,LOGIN_USER,user["username"].asCString(),user["password"].asCString());
        MYSQL_RES* res = NULL;

        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql,sql);
            if(ret == false)
            {
                ELOG("user login failed!");
                return false;
            }

            res = mysql_store_result(_mysql);
            if(res == NULL)
            {
                DLOG("there is no login info!");
                return false;
            }
        }

        int row_num = mysql_num_rows(res);
        if(row_num != 1)
        {
            DLOG("sql:%s",sql);
            DLOG("login user info is not unique!there are %d rows!",row_num);
            return false;
        }

        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = (Json::UInt64)std::stol(row[0]);
        user["score"] = std::stoi(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        mysql_free_result(res);
        return true;
    }

    // 通过用户名获取用户信息
    bool select_by_name(const std::string &name, Json::Value &user)
    {
        #define USER_BY_NAME "select id,score,total_count,win_count from user where username='%s';"
        char sql[4096] = {0};
        sprintf(sql,USER_BY_NAME,name.c_str());

        MYSQL_RES* res = NULL;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql,sql);
            if(ret == false)
            {
                ELOG("get user by name failed!");
                return false;
            }

            res = mysql_store_result(_mysql);
            if(res == NULL)
            {
                DLOG("there is no user info!");
                return false;
            }
        }

        int row_num = mysql_num_rows(res);
        if(row_num != 1)
        {
            DLOG("user info is not unique!");
            return false;
        }

        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = (Json::UInt64)std::stol(row[0]);
        user["username"] = name;
        user["score"] = std::stoi(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        mysql_free_result(res);
        return true;
    }

    // 通过用户ID获取用户信息
    bool select_by_id(uint64_t id, Json::Value &user)
    {
        #define USER_BY_ID "select username,score,total_count,win_count from user where id=%ld;"
        char sql[4096] = {0};
        sprintf(sql,USER_BY_ID,id);
        
        MYSQL_RES* res = NULL;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql,sql);
            if(ret == false)
            {
                ELOG("get user by id failed!");
                return false;
            }

            res = mysql_store_result(_mysql);
            if(res == NULL)
            {
                DLOG("there is no user info!");
                return false;
            }
        }

        int row_num = mysql_num_rows(res);
        if(row_num != 1)
        {
            DLOG("user info is not unique!");
            return false;
        }

        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = (Json::UInt64)id;
        user["username"] = row[0];
        user["score"] = std::stoi(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        mysql_free_result(res);
        return true;
    }

    // 胜利时天梯分数增加30分，战斗场次增加1，胜利场次增加1
    bool win(uint64_t id)
    {
        #define USER_WIN "update user set score=score+30,total_count=total_count+1,win_count=win_count+1 where id=%ld;"
        char sql[4096] = {0};
        sprintf(sql,USER_WIN,id);
        bool ret = mysql_util::mysql_exec(_mysql,sql);
        if(ret == false)
        {
            ELOG("update winner info failed!");
            return false;
        }
        return true;
    }

    // 失败时天梯分数减少30，战斗场次增加1，其他不变
    bool lose(uint64_t id)
    {
        #define USER_LOSE "update user set score=score-30,total_count=total_count+1 where id=%ld;"
        char sql[4096] = {0};
        sprintf(sql,USER_LOSE,id);
        bool ret = mysql_util::mysql_exec(_mysql,sql);
        if(ret == false)
        {
            ELOG("update loser info failed!");
            return false;
        }
        return true;
    }
};

#endif